#include <gtk/gtk.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>       
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <cairo.h>
#include <math.h>
#include "YUVConversion.h"


#define DISPLAY_WIDTH 1280
#define DISPLAY_HEIGHT 720
GtkWidget *drawingarea;
GtkWidget *window;
int frameWidth = 320;
int frameHight = 240;
static GtkWidget *entry;

GdkPixbuf *pixbuff;
char fileName[200] = "";
int fmtName = FMT_UYVY;
int frameSeek = 0;
unsigned char *src_data;
unsigned char *des_data;
int oneFrameSize = 2560*1600*4;

int loadFromFile(char fileName[], int frameSeek, int format, int width, int height)
{
    int ret;
    int aSrcFrameLength = 0;
    int aDesFrameLength = 0;
    printf("fileName=%s frameSeek=%d FMT=%d width=%d height=%d\n", fileName, frameSeek, format, width, height);

    if( format == FMT_NONE || width == 0 || height == 0)
    {
        printf("return -1 : FMT=%d width=%d height=%d\n", FMT_NONE, width, height);
        return -1;
    }

    
    int fd = open(fileName, O_RDWR,0777);
    if ( fd <= 0 )
    {
        perror("open file failed");
        return -1;
    }

    switch(format)
    {
        case FMT_YUYV:
            aSrcFrameLength = width * height * 2;
        break;
        case FMT_YVYU:
            aSrcFrameLength = width * height * 2;
        break;
        case FMT_UYVY:
            aSrcFrameLength = width * height * 2;
        break;
        case FMT_VYUY:
            aSrcFrameLength = width * height * 2;
        break;
        case FMT_NV12:
            aSrcFrameLength = width * height * 3 / 2;
        break;
        case FMT_NV21:
            aSrcFrameLength = width * height * 3 / 2;
        break;
    }

    //移动到指定位置, 偏移的帧数
    lseek(fd, frameSeek*aSrcFrameLength, SEEK_SET);

    if ( (ret = read(fd, src_data, aSrcFrameLength)) == -1) {
        perror("read:");  
        goto exitLoadErr;
    }
    else
    {
        printf("frameSeek=%d   ret=%d\n", frameSeek, ret);
    }

    /* 按照制定的格式进行数据的装换 */
    switch(format)
    {
        case FMT_YUYV:
            yuv422packed_to_rgb24( FMT_YUYV, src_data, des_data, width, height);  
        break;
        case FMT_YVYU:
            yuv422packed_to_rgb24( FMT_YVYU, src_data, des_data, width, height);  
        break;
        case FMT_UYVY:
            yuv422packed_to_rgb24( FMT_UYVY, src_data, des_data, width, height);  
        break;
        case FMT_VYUY:
            yuv422packed_to_rgb24( FMT_VYUY, src_data, des_data, width, height);  
        break;
        case FMT_NV12:
            yuv420sp_to_rgb24(FMT_NV12,src_data, des_data, width, height);
        break;
        case FMT_NV21:
            yuv420sp_to_rgb24(FMT_NV21,src_data, des_data, width, height);
        break;
    }

    printf("conversion OK : width=%d height=%d aSrcFrameLength=%d\n", width, height, aSrcFrameLength);
    
    /* 从字节数据中创建pixbuff */
    pixbuff = gdk_pixbuf_new_from_data ((guchar* )des_data, GDK_COLORSPACE_RGB, 
            FALSE, 8, width, height, width*3, 0, 0);

    if ( pixbuff == NULL )
    {
        perror("gdk_pixbuf_new_from_data ERR:");
        goto exitLoadErr;
    }
    else
    {
        printf("gdk_pixbuf_new_from_data OK:");
    }

exitLoadErr:
    if ( fd > 0 )
    {
        close(fd);
    }
    
    return 0;
}


static gboolean on_window_draw ()
{
    cairo_t *cr = NULL;
    /* 从文件中指定位置加载数据 */
    if ( loadFromFile( fileName, frameSeek, fmtName, frameWidth, frameHight) == -1 )
    {
        printf("loadFromFile false\n");
        return false;
    }


    cr = gdk_cairo_create (gtk_widget_get_window(drawingarea));
    if ( cr == NULL )
    {
        perror("gdk_cairo_create false:\n");
        return false;
    }
    gdk_cairo_set_source_pixbuf(cr, pixbuff, 0, 0);
    cairo_paint(cr);
    cairo_destroy (cr);

    return true;
}


static gboolean on_drawarea_draw (GtkWidget *da, GdkEvent *event, gpointer data)
{
    if ( on_window_draw() == true )
    {
        printf("on_drawarea_draw true\n");
        return true;
    }
    printf("on_drawarea_draw false\n");
    return false;
}


void PressFormatSelect(GtkMenuItem *item,gpointer data)
{
    const gchar * format = gtk_menu_item_get_label (item);
    if ( strcmp("FMT_VYUY", format) == 0)
    {
        fmtName = FMT_VYUY;
    }
    else if ( strcmp("FMT_UYVY", format) == 0)
    {
        fmtName = FMT_UYVY;
    }
    else if ( strcmp("FMT_YVYU", format) == 0)
    {
        fmtName = FMT_YVYU;
    }
    else if ( strcmp("FMT_YUYV", format) == 0)
    {
        fmtName = FMT_YUYV;
    }
    else if ( strcmp("FMT_NV12", format) == 0)
    {
        fmtName = FMT_NV12;
    }
    else if ( strcmp("FMT_NV21", format) == 0)
    {
        fmtName = FMT_NV21;
    }

    printf("Format=%s\n", format);

    on_window_draw();
}


void PressSizeSelect(GtkMenuItem *item,gpointer data)
{
    const gchar * size = gtk_menu_item_get_label (item);
    if ( strcmp("800x480" , size ) == 0)
    {
        frameWidth = 800;
        frameHight = 480;
    }
    else if ( strcmp("960x540" , size ) == 0)
    {
        frameWidth = 960;
        frameHight = 540;
    }
    else if ( strcmp("1024x600" , size ) == 0)
    {
        frameWidth = 1024;
        frameHight = 600;
    }
    else if ( strcmp("1280x800" , size ) == 0)
    {
        frameWidth = 1280;
        frameHight = 800;
    }
    else if ( strcmp("1280x1024" , size ) == 0)
    {
        frameWidth = 1280;
        frameHight = 1024;
    }
    else if ( strcmp("1280x720" , size ) == 0)
    {
        frameWidth = 1280;
        frameHight = 720;
    }
    else if ( strcmp("1380x520" , size ) == 0)
    {
        frameWidth = 1380;
        frameHight = 520;
    }
    else if ( strcmp("1440x900" , size ) == 0)
    {
        frameWidth = 1440;
        frameHight = 900;
    }
    else if ( strcmp("1366x768" , size ) == 0)
    {
        frameWidth = 1366;
        frameHight = 768;
    }
    else if ( strcmp("1680x1050" , size ) == 0)
    {
        frameWidth = 1680;
        frameHight = 1050;
    }
    else if ( strcmp("1920x1080" , size ) == 0)
    {
        frameWidth = 1920;
        frameHight = 1080;
    }
    else if ( strcmp("1920x1200" , size ) == 0)
    {
        frameWidth = 1920;
        frameHight = 1200;
    }
    else if ( strcmp("2560x1440" , size ) == 0)
    {
        frameWidth = 2560;
        frameHight = 1440;
    }
    else if ( strcmp("2560x1600" , size ) == 0)
    {
        frameWidth = 2560;
        frameHight = 1600;
    }

    printf("frameWidth=%d  frameHight=%d\n", frameWidth, frameHight);
    gtk_widget_set_size_request(GTK_WIDGET(window), frameWidth, frameHight);
    gtk_widget_set_size_request(GTK_WIDGET(drawingarea), frameWidth, frameHight);
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);
    on_window_draw();
}


void gtk_open(GtkMenuItem *item,gpointer data)
{
    GtkWidget *dialog;
    GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
    gint res;

    dialog = gtk_file_chooser_dialog_new ("Open File", GTK_WINDOW(data ),\
      action, ("_Cancel"),GTK_RESPONSE_CANCEL, ("_Open"), GTK_RESPONSE_ACCEPT, NULL);

    res = gtk_dialog_run (GTK_DIALOG (dialog));
    if (res == GTK_RESPONSE_ACCEPT)
    {
        char *filename;
        GtkFileChooser *chooser = GTK_FILE_CHOOSER (dialog);
        filename = gtk_file_chooser_get_filename (chooser);
        strcpy(fileName, filename);
        g_free (filename);
    }

    gtk_widget_destroy (dialog);
    on_window_draw();
}

void framePlus(GtkMenuItem *item,gpointer data)
{
    frameSeek++;
    printf("Now frame is %d\n", frameSeek);

    on_window_draw();
}


void frameSub(GtkMenuItem *item,gpointer data)
{
    frameSeek--;
    if( frameSeek < 0 )
    {   
        frameSeek = 0;
    }
    printf("Now frame is %d\n", frameSeek);
    
    on_window_draw();
}

//主函数:main()
int main(int argc,char* argv[])
{
    /*创建指向GtkWidget类型的指针*/
    GtkWidget *tempWidget;
    GtkWidget *imageItem;
    GtkBuilder *builder = NULL;
    GtkWidget *fileChooseDialog;

    /*初始化*/
    gtk_init(&argc,&argv);

    //分配内存
    src_data = (unsigned char *)malloc(oneFrameSize*sizeof(unsigned char));
    if ( src_data == NULL )
    {
        perror("src_data-malloc:");
        return -1;;
    }

    des_data = (unsigned char *)malloc(oneFrameSize*sizeof(unsigned char));
    if( des_data == NULL )
    {
        perror("des_data-malloc:");
        return -1;;
    }

    /* 从Glade中加载界面 */
    builder=gtk_builder_new();
    gtk_builder_add_from_file(builder,"glade.glade",NULL);
    gtk_builder_connect_signals(builder, NULL);

    /* 根据 ID 获取子构件 */
    window=GTK_WIDGET(gtk_builder_get_object(builder,"window")); 
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);
    gtk_window_set_default_size(GTK_WINDOW(window), DISPLAY_WIDTH, DISPLAY_HEIGHT);
    // gtk_window_set_resizable(GTK_WINDOW(window), true);

    drawingarea = GTK_WIDGET(gtk_builder_get_object(builder,"drawingarea"));
    gtk_widget_set_size_request(GTK_WIDGET(drawingarea), DISPLAY_WIDTH, DISPLAY_HEIGHT);
    g_signal_connect (G_OBJECT (drawingarea), "draw", \
        G_CALLBACK(on_drawarea_draw), NULL);

    tempWidget = GTK_WIDGET(gtk_builder_get_object(builder,"imagemenuitemOpen"));
    g_signal_connect(tempWidget, "activate", G_CALLBACK(gtk_open), window);

    tempWidget = GTK_WIDGET(gtk_builder_get_object(builder,"imagemenuitemQuit"));
    g_signal_connect(tempWidget, "activate", G_CALLBACK(gtk_main_quit), NULL);

    imageItem = GTK_WIDGET(gtk_builder_get_object(builder,"imagemenuitemUYVY"));
    g_signal_connect(imageItem, "activate", G_CALLBACK(PressFormatSelect), NULL);
    imageItem = GTK_WIDGET(gtk_builder_get_object(builder,"imagemenuitemYUYV"));
    g_signal_connect(imageItem, "activate", G_CALLBACK(PressFormatSelect), NULL);
    imageItem = GTK_WIDGET(gtk_builder_get_object(builder,"imagemenuitemYVYU"));
    g_signal_connect(imageItem, "activate", G_CALLBACK(PressFormatSelect), NULL);
    imageItem = GTK_WIDGET(gtk_builder_get_object(builder,"imagemenuitemVYUY"));
    g_signal_connect(imageItem, "activate", G_CALLBACK(PressFormatSelect), NULL);
    imageItem = GTK_WIDGET(gtk_builder_get_object(builder,"imagemenuitemNV12"));
    g_signal_connect(imageItem, "activate", G_CALLBACK(PressFormatSelect), NULL);
    imageItem = GTK_WIDGET(gtk_builder_get_object(builder,"imagemenuitemNV21"));
    g_signal_connect(imageItem, "activate", G_CALLBACK(PressFormatSelect), NULL);
    

    imageItem = GTK_WIDGET(gtk_builder_get_object(builder,"800x480"));
    g_signal_connect(imageItem, "activate", G_CALLBACK(PressSizeSelect), NULL);
    imageItem = GTK_WIDGET(gtk_builder_get_object(builder,"960x540"));
    g_signal_connect(imageItem, "activate", G_CALLBACK(PressSizeSelect), NULL);
    imageItem = GTK_WIDGET(gtk_builder_get_object(builder,"1024x600"));
    g_signal_connect(imageItem, "activate", G_CALLBACK(PressSizeSelect), NULL);
    imageItem = GTK_WIDGET(gtk_builder_get_object(builder,"1280x800"));
    g_signal_connect(imageItem, "activate", G_CALLBACK(PressSizeSelect), NULL);
    imageItem = GTK_WIDGET(gtk_builder_get_object(builder,"1280x1024"));
    g_signal_connect(imageItem, "activate", G_CALLBACK(PressSizeSelect), NULL);
    imageItem = GTK_WIDGET(gtk_builder_get_object(builder,"1280x720"));
    g_signal_connect(imageItem, "activate", G_CALLBACK(PressSizeSelect), NULL);
    imageItem = GTK_WIDGET(gtk_builder_get_object(builder,"1380x520"));
    g_signal_connect(imageItem, "activate", G_CALLBACK(PressSizeSelect), NULL);
    imageItem = GTK_WIDGET(gtk_builder_get_object(builder,"1440x900"));
    g_signal_connect(imageItem, "activate", G_CALLBACK(PressSizeSelect), NULL);
    imageItem = GTK_WIDGET(gtk_builder_get_object(builder,"1366x768"));
    g_signal_connect(imageItem, "activate", G_CALLBACK(PressSizeSelect), NULL);
    imageItem = GTK_WIDGET(gtk_builder_get_object(builder,"1680x1050"));
    g_signal_connect(imageItem, "activate", G_CALLBACK(PressSizeSelect), NULL);
    imageItem = GTK_WIDGET(gtk_builder_get_object(builder,"1920x1080"));
    g_signal_connect(imageItem, "activate", G_CALLBACK(PressSizeSelect), NULL);
    imageItem = GTK_WIDGET(gtk_builder_get_object(builder,"1920x1200"));
    g_signal_connect(imageItem, "activate", G_CALLBACK(PressSizeSelect), NULL);
    imageItem = GTK_WIDGET(gtk_builder_get_object(builder,"2560x1440"));
    g_signal_connect(imageItem, "activate", G_CALLBACK(PressSizeSelect), NULL);
    imageItem = GTK_WIDGET(gtk_builder_get_object(builder,"2560x1600"));
    g_signal_connect(imageItem, "activate", G_CALLBACK(PressSizeSelect), NULL);
    
    imageItem = GTK_WIDGET(gtk_builder_get_object(builder,"menuitemFrame+"));
    g_signal_connect(imageItem, "activate", G_CALLBACK(framePlus), NULL);
    imageItem = GTK_WIDGET(gtk_builder_get_object(builder,"menuitemFrame-"));
    g_signal_connect(imageItem, "activate", G_CALLBACK(frameSub), NULL);

    /* 释放builder对象 */
    g_object_unref(G_OBJECT(builder)); 
    gtk_widget_realize(drawingarea);
    gtk_widget_show_all(window);
    gtk_main();


    if( src_data != NULL )
    {
        free(src_data);
    }

    if( des_data != NULL )
    {
        free(des_data);
    }

    printf("exit success\n");
    return 0;
}
